﻿using System.Collections;
using Basic.FormCollect.Model;
using Basic.FormExtendService;
using Basic.FormModel;
using Basic.FormModel.Conditional;
using Basic.FormModel.QueryColumn;
using Basic.FormRemoteModel;
using Basic.FormRemoteModel.QueryForm.Model;
using Basic.HrRemoteModel;
using Basic.HrRemoteModel.Dept.Model;
using Basic.HrRemoteModel.DicItem.Model;
using Basic.HrRemoteModel.Emp.Model;
using Basic.HrRemoteModel.TreeDic.Model;
using Basic.UserFormService.Interface;
using SqlSugar;
using WeDonekRpc.Helper;

namespace Basic.UserFormService.PhysicsTable
{
    internal class FilterQueryService : IFilterQueryService
    {
        private class QueryCol
        {
            public string name;
            public string table;
            public PhyTableDataType dataType;
            public PhyColShowMode showMode;
            public long? dicId;
            public List<KeyValuePair<string, string>> Items;
        }
        private readonly ITreeDicService _TreeDic;
        private readonly IUnitDeptService _Dept;
        private readonly IEmpService _Emp;
        private readonly IDictItemService _DictItem;

        public FilterQueryService ( ITreeDicService treeDic,
            IUnitDeptService dept,
            IEmpService emp,
            IDictItemService dictItem )
        {
            this._TreeDic = treeDic;
            this._Dept = dept;
            this._Emp = emp;
            this._DictItem = dictItem;
        }

        public bool IsNull { get; set; } = false;

        private long _CompanyId = 0;
        public List<IConditionalModel> ToWhere ( PhysicsFormBody body, long companyId, SearchParam[] param )
        {
            if ( param.IsNull() )
            {
                return null;
            }
            this._CompanyId = companyId;
            List<IConditionalModel> list = new List<IConditionalModel>();
            list.Add(new ConditionalExtendModel
            {
                ConditionalType = ConditionalType.Equal,
                DbType = System.Data.DbType.Int64,
                FieldName = ConstDic.CompanyIdColName,
                FieldValue = companyId.ToString(),
                Table = null
            });
            foreach ( SearchParam c in param )
            {
                if ( c.ColId.Length == 1 )
                {
                    QueryCol col = this._GetColumn(body, c.ColId[0]);
                    IConditionalModel model = this._GetConditional(col, c);
                    if ( model == null )
                    {
                        this.IsNull = true;
                        return null;
                    }
                    list.Add(model);
                }
                else
                {
                    ConditionalCollections collects = new ConditionalCollections();
                    collects.ConditionalList = new List<KeyValuePair<WhereType, ConditionalModel>>();
                    foreach ( long a in c.ColId )
                    {
                        QueryCol col = this._GetColumn(body, a);
                        ConditionalModel model = this._GetConditional(col, c);
                        if ( model != null )
                        {
                            collects.ConditionalList.Add(new KeyValuePair<WhereType, ConditionalModel>(WhereType.Or, model));
                        }
                    }
                    if ( collects.ConditionalList.Count > 0 )
                    {
                        list.Add(collects);
                    }
                    else
                    {
                        this.IsNull = true;
                        return null;
                    }
                }
            }
            return list;
        }
        private HrLinkType _GetLinkType ( QueryFilterMode type )
        {
            if ( type == QueryFilterMode.Link )
            {
                return HrLinkType.link;
            }
            else if ( type == QueryFilterMode.StartsWith )
            {
                return HrLinkType.startsWith;
            }
            else if ( type == QueryFilterMode.EndsWith )
            {
                return HrLinkType.endsWith;
            }
            return HrLinkType.equals;
        }
        private ConditionalModel _SearchEmp ( QueryCol col, SearchParam param )
        {
            HrLinkType type = this._GetLinkType(param.Mode);
            long[] empId = this._Emp.FindEmpId(new EmpFindParam
            {
                EmpName = param.Val,
                CompanyId = this._CompanyId,
                LinkType = type
            });
            if ( empId.IsNull() )
            {
                return null;
            }
            else if ( empId.Length == 1 )
            {
                return new ConditionalExtendModel
                {
                    ConditionalType = ConditionalType.Equal,
                    DbType = System.Data.DbType.Int64,
                    FieldValue = empId[0].ToString(),
                    FieldName = col.name,
                    Table = col.table
                };
            }
            return new ConditionalExtendModel
            {
                ConditionalType = ConditionalType.In,
                DbType = System.Data.DbType.Int64,
                Vals = empId,
                FieldName = col.name,
                Table = col.table
            };
        }
        private ConditionalModel _SearchDept ( QueryCol col, SearchParam param )
        {
            HrLinkType type = this._GetLinkType(param.Mode);
            bool? isUnit = null;
            if ( col.showMode == PhyColShowMode.DeptName )
            {
                isUnit = false;
            }
            else if ( col.showMode == PhyColShowMode.UnitName )
            {
                isUnit = true;
            }
            long[] deptId = this._Dept.FindDeptId(new DeptFindParam
            {
                Name = param.Val,
                CompanyId = this._CompanyId,
                IsUnit = isUnit,
                LinkType = type,
            });
            if ( deptId.IsNull() )
            {
                return null;
            }
            else if ( deptId.Length == 1 )
            {
                return new ConditionalExtendModel
                {
                    ConditionalType = ConditionalType.Equal,
                    DbType = System.Data.DbType.Int64,
                    FieldValue = deptId[0].ToString(),
                    FieldName = col.name,
                    Table = col.table
                };
            }
            return new ConditionalExtendModel
            {
                ConditionalType = ConditionalType.In,
                DbType = System.Data.DbType.Int64,
                Vals = deptId,
                FieldName = col.name,
                Table = col.table
            };
        }

        private ConditionalModel _SearchDictItem ( QueryCol col, SearchParam param )
        {
            string[] vals = null;
            if ( param.Mode == QueryFilterMode.EndsWith )
            {
                vals = col.Items.Convert(c => c.Key.EndsWith(param.Val), c => c.Value);
            }
            else if ( param.Mode == QueryFilterMode.Link )
            {
                vals = col.Items.Convert(c => c.Key.Contains(param.Val), c => c.Value);
            }
            else if ( param.Mode == QueryFilterMode.StartsWith )
            {
                vals = col.Items.Convert(c => c.Key.StartsWith(param.Val), c => c.Value);
            }
            else
            {
                vals = col.Items.Convert(c => c.Key == param.Val, c => c.Value);
            }
            if ( vals.IsNull() )
            {
                return null;
            }
            else if ( vals.Length == 1 )
            {
                return new ConditionalExtendModel
                {
                    ConditionalType = ConditionalType.Equal,
                    DbType = System.Data.DbType.String,
                    FieldValue = vals[0],
                    FieldName = col.name,
                    Table = col.table
                };
            }
            return new ConditionalExtendModel
            {
                ConditionalType = ConditionalType.In,
                DbType = System.Data.DbType.String,
                Vals = vals,
                FieldName = col.name,
                Table = col.table
            };
        }
        private ConditionalModel _SearchDict ( QueryCol col, SearchParam param )
        {
            HrLinkType type = this._GetLinkType(param.Mode);
            string[] vals = this._DictItem.FindDictValue(new DicItemFind
            {
                DicId = col.dicId.Value,
                Text = param.Val,
                LinkType = type,
            });
            if ( vals.IsNull() )
            {
                return null;
            }
            else if ( vals.Length == 1 )
            {
                return new ConditionalExtendModel
                {
                    ConditionalType = ConditionalType.Equal,
                    DbType = System.Data.DbType.String,
                    FieldValue = vals[0],
                    FieldName = col.name,
                    Table = col.table
                };
            }
            return new ConditionalExtendModel
            {
                ConditionalType = ConditionalType.In,
                DbType = System.Data.DbType.String,
                Vals = vals,
                FieldName = col.name,
                Table = col.table
            };
        }
        private ConditionalModel _SearchTreeDict ( QueryCol col, SearchParam param )
        {
            HrLinkType type = this._GetLinkType(param.Mode);
            string[] vals = this._TreeDic.FindDictValue(new TreeDicItemFind
            {
                DicId = col.dicId.Value,
                Text = param.Val,
                LinkType = type,
            });
            if ( vals.IsNull() )
            {
                return null;
            }
            else if ( vals.Length == 1 )
            {
                return new ConditionalExtendModel
                {
                    ConditionalType = ConditionalType.Equal,
                    DbType = System.Data.DbType.String,
                    FieldValue = vals[0],
                    FieldName = col.name,
                    Table = col.table
                };
            }
            return new ConditionalExtendModel
            {
                ConditionalType = ConditionalType.In,
                DbType = System.Data.DbType.Int64,
                Vals = vals,
                FieldName = col.name,
                Table = col.table
            };
        }
        private ConditionalModel _GetConditional ( QueryCol col, SearchParam param )
        {
            if ( col.showMode == PhyColShowMode.EmpName )
            {
                return this._SearchEmp(col, param);
            }
            else if ( col.showMode == PhyColShowMode.DeptName || col.showMode == PhyColShowMode.UnitName || col.showMode == PhyColShowMode.DeptAndUnit )
            {
                return this._SearchDept(col, param);
            }
            else if ( col.showMode == PhyColShowMode.DictItem )
            {
                return this._SearchDictItem(col, param);
            }
            else if ( col.showMode == PhyColShowMode.DictItemName )
            {
                return this._SearchDict(col, param);
            }
            else if ( col.showMode == PhyColShowMode.DictTreeName )
            {
                return this._SearchTreeDict(col, param);
            }
            ConditionalExtendModel obj = new ConditionalExtendModel
            {
                FieldName = col.name,
                Table = col.table
            };
            if ( col.dataType == PhyTableDataType.Array )
            {
                obj.ConditionalType = ConditionalType.InLike;
                if ( !param.Vals.IsNull() )
                {
                    obj.Vals = param.Vals.ConvertAll(a => "%|" + a + "|%");
                }
                else
                {
                    obj.FieldValue = "%|" + param.Val + "|%";
                }
                obj.DbType = System.Data.DbType.String;
            }
            else if ( param.Mode == QueryFilterMode.Between )
            {
                obj.DbType = col.dataType.GetDbType();
                obj.Func = "between";
                if ( obj.DbType == System.Data.DbType.DateTime || obj.DbType == System.Data.DbType.Date )
                {
                    obj.Vals = new object[]
                    {
                        Tools.PaseDateTime(param.Vals[0]),
                        Tools.PaseDateTime(param.Vals[1])
                    };
                }
                else
                {
                    obj.Vals = new object[]
                   {
                        param.Vals[0],
                        param.Vals[1]
                   };
                }
            }
            else if ( !param.Vals.IsNull() )
            {
                obj.ConditionalType = ConditionalType.In;
                obj.Vals = param.Vals;
                obj.DbType = col.dataType.GetDbType();
            }
            else
            {
                obj.ConditionalType = param.Mode.GetConditionalType();
                obj.DbType = col.dataType.GetDbType();
                obj.FieldValue = param.Val;
            }
            return obj;
        }


        private QueryCol _GetColumn ( PhysicsFormBody body, long colId )
        {
            PhysicsQueryColumn col = this._FindColumn(body, colId, out string table);
            QueryCol c = new QueryCol
            {
                name = col.ColName,
                dataType = col.DataType,
                showMode = col.ShowMode,
                table = table,
                dicId = col.DictId,
            };
            if ( col.ShowMode == PhyColShowMode.Column )
            {
                return c;
            }
            PhysicsQueryColumn sour = body.Main.Column[col.SourceCol.Value];
            c.name = sour.ColName;
            if ( col.ShowMode == PhyColShowMode.DictTreeName || col.ShowMode == PhyColShowMode.DictItemName )
            {
                c.dicId = sour.DictId;
            }
            else if ( col.ShowMode == PhyColShowMode.DictItem && col.ColumnSet.TryGetValue("Items", out object val) )
            {
                IList itemList = (IList)val;
                c.Items = new List<KeyValuePair<string, string>>(itemList.Count);
                foreach ( IDictionary<string, object> i in itemList )
                {
                    object v = i["value"];
                    c.Items.Add(new KeyValuePair<string, string>(Convert.ToString(i["text"]), v == null ? string.Empty : Convert.ToString(v)));
                }
            }
            return c;
        }
        private PhysicsQueryColumn _FindColumn ( PhysicsFormBody body, long colId, out string table )
        {
            if ( body.Main.Column.TryGetValue(colId, out PhysicsQueryColumn col) )
            {
                table = null;
                return col;
            }
            foreach ( PhysicsQueryTable item in body.Children )
            {
                if ( item.Column.TryGetValue(colId, out col) )
                {
                    table = item.TableName;
                    return col;
                }
            }
            throw new ErrorException("form.physics.column.not.find");
        }

    }
}
